// alloc policy
// $Id: mem_util.h 693 2011-03-28 17:38:40Z Oleg.Bulychov $
#pragma once

#include <string.h>
#include "type_util.h"

namespace mem_util
{
    enum
    {
        MEM_GRANULARITY  = 4,//x86 only
        MEM_PAGE_SIZE = 4096,//x86 only, TODO detect
    };
//.............................................................................
    template<int min_cap = 4>
    struct malloc_policy
    {
        static size_t New_Capacity(size_t new_cap) NO_THROW_()
        {
            if (new_cap < min_cap)
                return min_cap;

            new_cap += new_cap / 2;

            return new_cap;
        }
//.............................................................................
        static void* Alloc(size_t cbsize) NO_THROW_()
        {
            return ::malloc(cbsize);
        }
//.............................................................................
        template<typename T>
        static T* Alloc(size_t count) NO_THROW_()
        {
            return (T*)Alloc(count * sizeof(T));
        }
//.............................................................................
        static void* Realloc(void* ptr, size_t cbsize) NO_THROW_()
        {
            return ::realloc(ptr, cbsize);
        }
//.............................................................................
        template<typename T>
        static T* Realloc(T* ptr, size_t count) NO_THROW_()
        {
            return (T*)Realloc((void*)ptr, count * sizeof(T));
        }
//.............................................................................
        static void Free(void* ptr) NO_THROW_()
        {
            return ::free(ptr);
        }
    };
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
    struct no_check_null_t
    {};
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T>
    inline void Uninitialized_Construct(T* begin, T* end, meta::int2type<0>) NO_THROW_()
    {//:nothing to do
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Uninitialized_Construct(T* begin, T* end, meta::int2type<1>)//class
    {
        //for (; begin != end; ++begin)
        //    new(begin) T;
        //:duff device
        switch ((end - begin) & 7u)
        {
        case 0:
            while (begin != end)
            {
                new(begin) T; ++begin;
        case 7: new(begin) T; ++begin;
        case 6: new(begin) T; ++begin;
        case 5: new(begin) T; ++begin;
        case 4: new(begin) T; ++begin;
        case 3: new(begin) T; ++begin;
        case 2: new(begin) T; ++begin;
        case 1: new(begin) T; ++begin;
            }
        }
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Uninitialized_Construct(T* begin, T* end)
    {
        Uninitialized_Construct(begin, end, meta::int2type<meta::is_class<T>::result>());
    }
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T>
    inline void Initialized_Destruct(T* begin, T* end, meta::int2type<0>) NO_THROW_()
    {//:nothing to do
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Initialized_Destruct(T* begin, T* end, meta::int2type<1>) NO_THROW_()
    {
        for (; begin != end; ++begin)
            begin->~T();
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Initialized_Destruct(T* begin, T* end) NO_THROW_()
    {
        Initialized_Destruct(begin, end, meta::int2type<meta::is_class<T>::result>());
    }
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T>
    inline void Initialized_Assign(T* dst, T* begin, T* end)
    {
        COMPILETIME_CHECK(meta::is_class<T>::result, only_classes_can_use_assign);
        if (begin <= dst && dst < end)
        {
            dst += end - begin;
            while (begin != end)
                *--dst = *--end;
        }
        else
        for (; begin != end; ++begin, ++dst)
            *dst = *begin;
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Uninitialized_Copy(T* dst, T* begin, T* end)
    {
        COMPILETIME_CHECK(meta::is_class<T>::result, only_classes_can_use_copy);
        ASSERT_(dst >= end || dst <= begin - (end - begin));
        for (; begin != end; ++begin, ++dst)
            new(dst) T(*begin);
    }
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T>
    inline void Copy(T* begin, T* end, T* rbegin, T* rend, meta::int2type<0>) NO_THROW_()
    {
        ::memcpy(begin, rbegin, (rend - rbegin) * sizeof(T));
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Copy(T* begin, T* end, T* rbegin, T* rend, meta::int2type<1>)//class
    {
        int size = (int)(end - begin);//w64
        Initialized_Assign(begin, rbegin, rbegin + size);
        Uninitialized_Copy(begin + size, rbegin + size, rend);
    }
//__________________________________________________________________________________
    template<typename T>
    inline void Copy(T* begin, T* end, T* rbegin, T* rend)
    {
        Copy(begin, end, rbegin, rend, meta::int2type<meta::is_class<T>::result>());
    }
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T, typename U>
    inline void Uninitialized_Fill(T* begin, T* end, U const& filler)
    {
        //for (; begin != end; ++begin)
        //    new(begin) T(filler);
        switch ((end - begin) & 7u)
        {
        case 0:
            while (begin != end)
            {
                new(begin) T(filler); ++begin;
        case 7: new(begin) T(filler); ++begin;
        case 6: new(begin) T(filler); ++begin;
        case 5: new(begin) T(filler); ++begin;
        case 4: new(begin) T(filler); ++begin;
        case 3: new(begin) T(filler); ++begin;
        case 2: new(begin) T(filler); ++begin;
        case 1: new(begin) T(filler); ++begin;
            }
        }
    }
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T>
    inline void Erase(T* from, T* to, T* end) NO_THROW_()
    {//TODO detect T::moveable
        Initialized_Destruct(from, to);
        ::memmove(from, to, (end - to) * sizeof(T));
    }
//__________________________________________________________________________________
//__________________________________________________________________________________
    template<typename T>
    inline void Insert(T* where, T* end)
    {//TODO detect T::moveable
        ::memmove(where + 1, where, (end - where) * sizeof(T));
        Uninitialized_Construct(where, where + 1);
    }
//__________________________________________________________________________________
}
//__________________________________________________________________________________
extern void Mem_Panic(size_t cbRequired, size_t* pcbAvailable);
//__________________________________________________________________________________

//EOF!
